﻿namespace Snipps.ViewModels.Filters
{
    using System;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.Linq;

    using Snipps.Core;
    using Snipps.Core.Entities;
    using Snipps.Infrastructure.Services;

    public class SnippetFilterViewModel : FilterViewModelBase
    {
        private readonly ISnippetsDataContext _snippetsDataContext;

        private readonly IList<Tag> _tags;

        private readonly IThreadingService _threadingService;

        private ProgrammingLang _currentProgrammingLang;

        private Snippet _newSnippet;

        public SnippetFilterViewModel(
            ISnippetsDataContext snippetsDataContext, IList<Tag> tags, IThreadingService threadingService)
        {
            _snippetsDataContext = snippetsDataContext;
            _tags = tags;
            _threadingService = threadingService;
            var notifableTags = tags as INotifyCollectionChanged;
            if (notifableTags != null)
            {
                notifableTags.CollectionChanged += Tags_CollectionChanged;
            }
        }

        public ProgrammingLang CurrentProgrammingLang
        {
            get
            {
                return _currentProgrammingLang;
            }

            set
            {
                SetProperty(ref _currentProgrammingLang, value, "CurrentProgrammingLang", OnCurrentProgrammingLangChanged);
            }
        }

        private void OnCurrentProgrammingLangChanged()
        {
            StartFilterWhenActive = true;
        }

        private void Tags_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            StartFilterWhenActive = true;
        }

        protected override void OnIsActiveChanged()
        {
            base.OnIsActiveChanged();

            if (IsActive)
            {
                if (StartFilterWhenActive)
                {
                    StartFiltering();
                    StartFilterWhenActive = false;
                }
            }
        }

        public override void StartFiltering()
        {
            if (IsBusy)
            {
                return;
            }

            base.StartFiltering();

            Func<IList<Snippet>> f = () => _snippetsDataContext.FilterSnippets(FilterText, _currentProgrammingLang, _tags);

            cancelFilteringAction = _threadingService.QueueExecution(f, GetSnippetsAsyncEnd, ExceptionCallback);
        }

        private void ExceptionCallback(Exception obj)
        {
            StopFiltering();
        }

        private void GetSnippetsAsyncEnd(IList<Snippet> snippets)
        {
            CompletionList.ClearFilteredItems();
            CreateNewSnipppet();

            if (snippets.All(x => !x.Equals(_newSnippet)))
            {
                CompletionList.FilteredItems.Add(_newSnippet);
            }

            _threadingService.QueueExecution(
                () =>
                    {
                        foreach (var snippetVM in snippets)
                        {
                            CompletionList.FilteredItems.Add(snippetVM);
                        }
                    }, 
                () =>
                    {
                        SelectBestMatchingItem();
                        IsBusy = false;
                    });
        }

        private void CreateNewSnipppet()
        {
            _newSnippet = new Snippet { Name = FilterText, ProgrammingLang = _currentProgrammingLang };
            _newSnippet.Tags.Clear();
            foreach (var tag in _tags)
            {
                _newSnippet.Tags.Add(tag);
            }
        }
    }
}